
# coding: utf-8

# In[ ]:


# 任务：依据2011年每天共享单车使用数据，对2012年每天使用人数cnt进行预测。
#### --CSDN学院--人工智能直通车--第七班--王大恒--2018/07/22    


# In[77]:


#数据文件：day.csv 包含2011年数据和2012年数据

#数据属性（字段）解释：
#Instant    记录号
#Dteday     日期
#Season     季节（1春天、2夏天、3秋天、4冬天）
#yr         年份（0：2011、 1：2012）
#mnth       月份（1-12）
##holiday    是否为节假日
#weekday    周几 （0-6）
##workingday 是否为工作日 1为工作日 0非工作日，即周末或者节假日）
#weathersit 天气（1晴天，多云 2雾天，阴天 3小雪小雨 4 大雨，大雪，大雾）
#temp       气温摄氏度
#atemp      体感温度
#hum        湿度
#windspeed  风速
#casual     非注册用户个数
#registered 注册用户个数
#cnt        给定日期（天）总租车人数，响应变量y

#属性筛选
# Instant   记录号，   只是记录序号，不是租赁单车相关属性，对分析无意义  需剔除该列
# Dteday    日期，     因为是预测每天的租赁量，并且连续对分析意义不大，  需剔除该列
# yr        年份，     对于每一年的数据值是一样的，对分析无意义          需剔除该列
#casual     非注册人数  casual+ registered=cnt                           需剔除该列
#registered 注册用户个数 casual+ registered=cnt                          需剔除该列

# Season    季节，     是类别性变量，不应该以1，2,3,4形式参与计算分析，  需onehot编码
#mnth       月份，     是类别性变量                                      需onehot编码
#weekday    周几，     取值不能以0,1,2,3，4,5,6形式参与计算分析          需onehot编码
#weathersit 天气，   取值1，2，3，4                                      需onehot编码

#holiday    是否节假日，取值只有0或1                                     使用原始值
#workingday 是否工作日，取值之后0或1                                     使用原始值
#temp       气温,                                                        使用原始值
#atemp      体感气温，                                                   使用原始值
#hum        湿度，                                                       使用原始值
#windspeed  风速，                                                       使用原始值

#cnt        每天人数                              


# # 一、 特征工程

# ### 1、导入必要的工具包

# In[319]:


import numpy as np  # 矩阵操作
import pandas as pd  # SQL数据处理
#from sklearn.metrics import r2_score  # 评价回归预测模型的性能
#import matplotlib.pyplot as plt  # 画图
#import seaborn as sns #可视化

#图形出现在Notebook里而不是新窗口，该语句在jupyter中才有效
#get_ipython().run_line_magic('matplotlib', 'inline')


# ### 2、加载数据

# In[320]:


# 加载文件中数据
#dpath = "C:/PycharmProjects/test/venv/mydata/bikedata/"
dpath="./data/"
#dpath = "./"
data = pd.read_csv(dpath+"day.csv")
# 观察前5行了解数据每列（特征）的概况以及数据是否有缺失
data.head()


# In[321]:


#查看数据信息
data.info()


# In[ ]:


数据完整无缺失。


# ### 3、数据探索

# In[322]:


#对数据值型特征，用常用统计量观察其分布（均值，标准差，最大值，最小值，分位数，中位数）
data.describe()


# In[323]:


#对类别型特征，观察其取值范围
categorical_features= ['season','mnth','weathersit','weekday']

for col in categorical_features:
    print("\n%s属性的不同取值和出现的次数"%col)
    print(data[col].value_counts())
    data[col]=data[col].astype('object')


# In[ ]:


这些类别型特征的取值不多，可采用one hot编码。


# ### 4、特征处理

# In[324]:


#对四个类别特征one hot处理
x_train_cat = data[categorical_features]
x_train_cat = pd.get_dummies(x_train_cat)
x_train_cat.head()


# In[325]:


#对数值型变量预处理
from sklearn.preprocessing import MinMaxScaler
mn_x=MinMaxScaler()
numerical_features=['temp','atemp','hum','windspeed']
#标准化为0-1之间的数
temp=mn_x.fit_transform(data[numerical_features])

x_train_num=pd.DataFrame(data=temp,columns=numerical_features)
x_train_num.head()


# In[326]:


#将26维的类别型特征、4维的数值型特征、1维的holiday、1维的workingday连起来，成为32维的特征
x_train=pd.concat([x_train_cat,x_train_num,data['holiday'],data['workingday']],axis=1,ignore_index=False)
x_train.head()


# In[327]:


#拼接上instant yr cnt 原有数据，将编码后的特征数据保存到新文件中TZ_day.csv
#instant 是记录的序号，yr是年份用于下一步数据划分，cnt用于数据训练
TZ_train=pd.concat([data['instant'],x_train,data['yr'],data['cnt']],axis=1,ignore_index=False)
#保存
TZ_train.to_csv(dpath+'TeZheng_day.csv',index=False)
#查看前五行信心
TZ_train.head()


# In[328]:


TZ_train.info()


# In[88]:


#数据经特征编码处理结束，保存为文件TeZheng_day.csv


# # 二、对新数据数据集进行回归分析

# ### 1、导入必要数据包

# In[329]:


#数据读取以及基本处理
#import pandas as pd #数据处理
#import numpy as np #矩阵操作

#引入模型：最小二乘线性回归，领回归（L2正则），Lasso(L1正则）
from sklearn.linear_model import LinearRegression,RidgeCV,LassoCV   #,ElasticNetCV

#模型评估
from sklearn.metrics import mean_squared_error
from sklearn.metrics import r2_score #评价回归预测模型的性能

#画图
import matplotlib.pyplot as plt


# ### 2、加载数据

# In[330]:


#读入数据
data_tezheng = pd.read_csv(dpath+"TeZheng_Day.csv")
#查看数据
data_tezheng.head()


# ### 3、选取训练数据及测试数据

# In[331]:


#取2011年的数据作为训练数据
train=data_tezheng[data_tezheng.yr==0] #训练数据

train.drop(['instant','yr'],axis=1,inplace=True)
print("train（训练）:"+str(train.shape))

#取2012年的数据作为测试数据
test=data_tezheng[data_tezheng.yr==1] #测试数据
#取testID备份留作后用
testID=test['instant']
#testCNT=test['cnt']

test.drop(['instant','yr'],axis=1,inplace=True)
print("test（测试）:"+str(test.shape))


# In[ ]:


两年的数据量相当，每天都有。


# In[332]:


#查看训练数据
train.head()


# ### 4、准备训练数据

# In[354]:


#取训练数据的X和y
y_train=train['cnt'] #训练集y
X_train=train
X_train=X_train.drop(['cnt'],axis=1) #训练集X

#取训测试据的X和y
y_test=test['cnt'] #测试集y
X_test=test
X_test=X_test.drop(['cnt'],axis=1) #测试集X

X_train.head()


# In[344]:


X_test.head()


# In[355]:


#数据标准化
from sklearn.preprocessing import StandardScaler

mean_y=y_train.mean()#原数据的均值
print("y_train的均值mean_y：",mean_y)

std_y=y_train.std()#原数据的标准差
print("y_train的标准差std_y：",std_y)

y_train=(y_train-mean_y)/std_y#标准化后的y_train
y_test=(y_test-mean_y)/std_y #标准化后的y_test

#标准化y_test的均值
mean_test_y=y_test.mean()
mean_diff=mean_test_y;
print("标准化后的均值差异:",mean_diff)


# ### 5、模型训练

# #### 最小二乘训练

# In[359]:


#1.生成学习器实例
lr=LinearRegression()
#2.在训练集上训练学习器
lr.fit(X_train,y_train)

#3.训练集测试，测试集测试
y_train_pred=lr.predict(X_train)#训练集预测
y_test_pred=lr.predict(X_test)#测试集预测
y_test_pred+=mean_diff


# In[360]:


#RMSE性能测试
rmse_train=np.sqrt(mean_squared_error(y_train,y_train_pred))#训练集上的均方误差根，衡量观测值同真值之间的偏差
rmse_test=np.sqrt(mean_squared_error(y_test,y_test_pred))#测试集上的均方误差根，衡量观测值同真值之间的偏差
print("训练集RMSE:",rmse_train)
print("测试集RMSE:",rmse_test)


# In[361]:


#r2_score性能测试
r2_score_train=r2_score(y_train,y_train_pred)#训练集拟合度
r2_score_test=r2_score(y_test,y_test_pred)#测试集拟合度
print("训练集r2_score:",r2_score_train)
print("测试集r2_score:",r2_score_test)


# In[ ]:


训练集上好一些，测试集上差一些。


# #### 领回归模型训练

# In[362]:


#1.生成学习器实例
alphas=[0.01,0.1,1,10,100,1000]
ridge=RidgeCV(alphas=alphas,store_cv_values=True)

#2.用训练数据度模型进行训练
ridge.fit(X_train,y_train)

#通过交叉验证得到的最佳超参数alpha
alpha=ridge.alpha_
print("最佳的超参alpha:",alpha)

#交叉验证估计的测试误差
mse_cv=np.mean(ridge.cv_values_,axis=0)
rmse_cv=np.sqrt(mse_cv)
print("cv of rmse:",min(rmse_cv))

#训练上测试，训练误差
y_train_pred=ridge.predict(X_train)
rmse_train=np.sqrt(mean_squared_error(y_train,y_train_pred))
#测试上测试，测试误差
y_test_pred = ridge.predict(X_test)
y_test_pred+=mean_diff
rmse_test=np.sqrt(mean_squared_error(y_test,y_test_pred))
print("训练集RMSE:",rmse_train)
print("测试集RMSE:",rmse_test)

r2_score_train=r2_score(y_train,y_train_pred)#训练集拟合度
r2_score_test=r2_score(y_test,y_test_pred)#测试集拟合度
print("训练集r2_score:",r2_score_train)
print("测试集r2_score:",r2_score_test)


# In[231]:


#绘制重要系数
coefs=pd.Series(ridge.coef_,index=X_train.columns)#Wj
print("收取"+str(sum(coefs!=0))+"个特征，并 消除了",str(sum(coefs==0))+"个特征")

#正系数值最大的10个特征和负系数最小值(绝对值大)的10个特征
imp_coefs=pd.concat([coefs.sort_values().head(10),coefs.sort_values().tail(10)])
imp_coefs.plot(kind="barh")
plt.title("Coefficients in the Ridge Model")
plt.show()

mse_mean=np.mean(ridge.cv_values_,axis=0)
plt.plot(np.log10(alphas),mse_mean.reshape(len(alphas),1))

plt.xlabel('log(alpha)')
plt.ylabel('mse')
plt.show()


# #### Lasso模型训练

# In[363]:


#生成学习器实例
lasso=LassoCV()
#训练
lasso.fit(X_train,y_train)
#超参
alpha=lasso.alpha_
print("最佳超参alpha:",alpha)

mses=np.mean(lasso.mse_path_,axis=1)
plt.plot(np.log10(lasso.alphas_),mses)
plt.xlabel('log(alpha)')
plt.ylabel('mse')
plt.show()

mse_cv=np.mean(lasso.mse_path_,axis=1)
rmse_cv=np.sqrt(mse_cv)
print("cv of rmse:",min(rmse_cv))

#绘制重要系数
coefs=pd.Series(lasso.coef_,index=X_train.columns)#Wj
print("Lasso模型收取"+str(sum(coefs!=0))+"个特征，并 消除了",str(sum(coefs==0))+"个特征")
#正系数值最大的10个特征和负系数最小值(绝对值大)的10个特征
imp_coefs=pd.concat([coefs.sort_values().head(10),coefs.sort_values().tail(10)])
imp_coefs.plot(kind="barh")
plt.title("Coefficients in the Lasso Model")
plt.show()

mses=np.mean(lasso.mse_path_,axis=1)
plt.plot(np.log10(lasso.alphas_),mses)
plt.xlabel('log(alpha)')
plt.ylabel('mse')
plt.show()

y_train_pred=lasso.predict(X_train)
rmse_train=np.sqrt(mean_squared_error(y_train,y_train_pred))
print("训练集RMSE:",rmse_train)

y_test_pred = lasso.predict(X_test)
y_test_pred+=mean_diff
rmse_test = np.sqrt(mean_squared_error(y_test,y_test_pred))
print("测试集RMSE:",rmse_test)

r2_score_train=r2_score(y_train,y_train_pred)
r2_score_test=r2_score(y_test,y_test_pred)
print("训练集r2_scor:",r2_score_train)
print("测试集r2_socre:",r2_score_test)


# ### 6、对测试集进行测试，生成提交文件

# In[382]:


#经过模型训练测试后，Lasso对测试集的预测效果比较好，所以采用Lasso模型对2012年人数进行预测
y_test_pred=lasso.predict(X_test)
y_test_pred+=mean_diff#标准化的预测值

#将标准化的预测值还原
print(mean_y)
y_test_pred=y_test_pred * std_y + mean_y 

#生成提交测试文件Sub.csv
df=pd.DataFrame({"instant":testID,"cnt":testCNT,'pre_cnt':y_test_pred})
df.to_csv(dpath+'Sub.csv')
df.info()


# In[383]:


#查看预测结果
df.drop(['instant'],axis=1,inplace=True)
df.head(20)

